package com.example.redis.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Component
public class RedisLock {

    private static final Logger log = LoggerFactory.getLogger(RedisLock.class);

    @Autowired
    private RedisLockRegistry redisLockRegistry;
    private static String REDIS_LOCK_KEY = "REDIS_LOCK_KEY_";
    /**
     * 锁超时时间，防止线程在入锁以后，无限的执行等待
     */
    private int EXPIRE_MSECS = 60 * 1000;
    /**
     * 锁等待时间，防止线程饥饿
     */
    private int TIMEOUT_MSECS = 10;


    private RedisLock() {
    }

    public RedisLock(String key) {
        this.REDIS_LOCK_KEY = this.REDIS_LOCK_KEY + key;
    }

    public RedisLock(String key, int timeoutMsecs) {
        this(key);
        this.TIMEOUT_MSECS = timeoutMsecs;
    }


    public Lock lock(String key) {
        Lock redisLock = null;
        try {
            if (!StringUtils.isEmpty(key)) {
                REDIS_LOCK_KEY = REDIS_LOCK_KEY + key;
            }
            redisLock = redisLockRegistry.obtain(REDIS_LOCK_KEY);
            boolean tryLock = redisLock.tryLock(EXPIRE_MSECS, TimeUnit.SECONDS);
            log.info(">>> redis lock:{}", tryLock);
        } catch (Exception e) {
            log.error("redis lock Exception", e);
        }
        return redisLock;
    }

    public Lock lock(String key, int timeoutMsecs) {
        Lock redisLock = null;
        try {
            if (!StringUtils.isEmpty(key)) {
                REDIS_LOCK_KEY = REDIS_LOCK_KEY + key;
            }
            redisLock = redisLockRegistry.obtain(REDIS_LOCK_KEY);
            if (timeoutMsecs > 0) {
                TIMEOUT_MSECS = timeoutMsecs;
            }
            boolean tryLock = redisLock.tryLock(TIMEOUT_MSECS, TimeUnit.SECONDS);
            log.info(">>> redis lock:{}", tryLock);
        } catch (Exception e) {
            log.error("redis lock Exception", e);
        }
        return redisLock;
    }

    public void unlock(Lock redisLock) {
        try {
            if (redisLock != null)
                redisLock.unlock();
        } catch (Exception e) {
            log.error("redis unlock Exception", e);
        }
    }


}
